package manager

import (
	"fmt"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

type ConnectionManager struct {
	mu    sync.RWMutex
	conns map[string]map[*websocket.Conn]ConnInfo // map[roomID]map[conn]info
}

type ConnInfo struct {
	Conn      *websocket.Conn
	ID        string
	UserId    string
	IsGaming  bool
	Camp      int
	ackMsgIds map[string]time.Time
	mu        sync.RWMutex
}

func NewConnectionManager() *ConnectionManager {
	return &ConnectionManager{
		conns: make(map[string]map[*websocket.Conn]ConnInfo),
	}
}

func (m *ConnectionManager) Register(conn *websocket.Conn, liveRoomID string, userId string) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if _, exists := m.conns[liveRoomID]; !exists {
		m.conns[liveRoomID] = make(map[*websocket.Conn]ConnInfo)
	}

	m.conns[liveRoomID][conn] = ConnInfo{
		Conn:      conn,
		ID:        liveRoomID,
		UserId:    userId,
		Camp:      -1,
		IsGaming:  false,
		ackMsgIds: make(map[string]time.Time),
	}

	fmt.Printf("Registered user %s in room %s\n", userId, liveRoomID)
}

func (m *ConnectionManager) Deregister(conn *websocket.Conn, liveRoomID string) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if conns, exists := m.conns[liveRoomID]; exists {
		if _, exists := conns[conn]; exists {
			delete(conns, conn)
			if len(conns) == 0 {
				delete(m.conns, liveRoomID)
			}
			fmt.Printf("Deregistered connection from room %s\n", liveRoomID)
		}
	}
}

func (m *ConnectionManager) Broadcast(data string, liveRoomID string) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	if conns, exists := m.conns[liveRoomID]; exists {
		// 异步发送避免阻塞主锁
		go func(connsCopy map[*websocket.Conn]ConnInfo) {
			for conn := range connsCopy {
				if err := conn.WriteMessage(websocket.TextMessage, []byte(data)); err != nil {
					m.Deregister(conn, liveRoomID)
				}
			}
		}(copyConnMap(conns))
	}
}

// 辅助方法：深拷贝连接map
func copyConnMap(src map[*websocket.Conn]ConnInfo) map[*websocket.Conn]ConnInfo {
	dst := make(map[*websocket.Conn]ConnInfo, len(src))
	for k, v := range src {
		dst[k] = v
	}
	return dst
}

func (m *ConnectionManager) TalkToOneUser(data string, conn *websocket.Conn) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	for roomID, connMap := range m.conns {
		if _, exists := connMap[conn]; exists {
			if err := conn.WriteMessage(websocket.TextMessage, []byte(data)); err != nil {
				m.Deregister(conn, roomID)
			}
			return
		}
	}
}

func (m *ConnectionManager) Conns() map[string]map[*websocket.Conn]ConnInfo {
	m.mu.RLock()
	defer m.mu.RUnlock()

	result := make(map[string]map[*websocket.Conn]ConnInfo)
	for roomID, connMap := range m.conns {
		result[roomID] = copyConnMap(connMap)
	}
	return result
}

func (m *ConnectionManager) GetConnInfo(conn *websocket.Conn) (ConnInfo, bool) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	for _, connMap := range m.conns {
		if info, exists := connMap[conn]; exists {
			return info, true
		}
	}
	return ConnInfo{}, false
}

func (m *ConnectionManager) MarkAck(msgId string, conn *websocket.Conn, liveRoomID string) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if conns, exists := m.conns[liveRoomID]; exists {
		if info, exists := conns[conn]; exists {
			info.mu.Lock()
			defer info.mu.Unlock()
			info.ackMsgIds[msgId] = time.Now()
		}
	}
}
